package com.example.micro_property_springboot.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.example.micro_property_springboot.mapper.AssetCheckDiffMapper;
import com.example.micro_property_springboot.mapper.AssetCheckPlanMapper;
import com.example.micro_property_springboot.pojo.AssetCheckPlan;
import com.example.micro_property_springboot.pojo.AssetInfo;
import com.example.micro_property_springboot.pojo.DTO.request.AssetCheckPlanCreateRequest;
import com.example.micro_property_springboot.pojo.DTO.request.AssetCheckPlanUpdateRequest;
import com.example.micro_property_springboot.service.AssetCheckDiffService;
import com.example.micro_property_springboot.service.AssetCheckItemService;
import com.example.micro_property_springboot.service.AssetCheckPlanService;
import com.example.micro_property_springboot.service.AssetInfoService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.List;
import java.util.UUID;
import java.util.stream.Collectors;

/**
 * 资产盘点计划服务实现类
 */
@Slf4j
@Service
public class AssetCheckPlanServiceImpl extends ServiceImpl<AssetCheckPlanMapper, AssetCheckPlan> implements AssetCheckPlanService {

    /**
     * 资产盘点项服务
     */
    private final AssetCheckItemService assetCheckItemService;

    /**
     * 资产信息服务
     */
    private final AssetInfoService assetInfoService;

    /**
     * 资产盘点差异服务
     */
    private final AssetCheckDiffService assetCheckDiffService;
    /**
     * 资产盘点差异映射器
     */
    private final AssetCheckDiffMapper assetCheckDiffMapper;

    /**
     * 资产盘点计划服务实现类构造函数
     * @param assetCheckItemService 资产盘点项服务
     * @param assetInfoService 资产信息服务
     * @param assetCheckDiffService 资产盘点差异服务
     * @param assetCheckDiffMapper 资产盘点差异映射器
     */
    public AssetCheckPlanServiceImpl(AssetCheckItemService assetCheckItemService,
                                     AssetInfoService assetInfoService,
                                     AssetCheckDiffService assetCheckDiffService, AssetCheckDiffMapper assetCheckDiffMapper) {
        this.assetCheckItemService = assetCheckItemService;
        this.assetInfoService = assetInfoService;
        this.assetCheckDiffService = assetCheckDiffService;
        this.assetCheckDiffMapper = assetCheckDiffMapper;
    }

    @Override
    @Transactional
    public AssetCheckPlan createAssetCheckPlan(AssetCheckPlanCreateRequest request) {
        log.info("开始创建盘点计划，请求参数：{}", request);

        // 验证请求参数
        validateCreateRequest(request);

        AssetCheckPlan plan = new AssetCheckPlan();
        plan.setPlanNo(generatePlanNo());
        plan.setCheckScope(request.getCheckScope());
        plan.setScopeId(request.getScopeId());
        plan.setCheckUserId(request.getCheckUserId());
        plan.setStartTime(request.getStartTime());
        plan.setEndTime(request.getEndTime());
        plan.setStatus("NOT_STARTED");
        plan.setCreateTime(LocalDateTime.now());
        plan.setUpdateTime(LocalDateTime.now());

        // 保存盘点计划
        save(plan);
        log.info("盘点计划创建成功，计划ID：{}，计划编号：{}", plan.getId(), plan.getPlanNo());

        // 根据盘点范围查询资产列表
        List<Long> assetIds = getAssetIdsByCheckScope(request.getCheckScope(), request.getScopeId());
        log.info("根据盘点范围查询到{}个资产", assetIds.size());

        if (assetIds.isEmpty()) {
            log.warn("盘点范围{}下没有找到任何资产，scopeId：{}", request.getCheckScope(), request.getScopeId());
        }

        // 创建盘点明细
        assetCheckItemService.createAssetCheckItems(plan.getId(), assetIds);
        log.info("盘点明细创建完成，计划ID：{}", plan.getId());

        return plan;
    }

    @Override
    @Transactional
    public AssetCheckPlan updateAssetCheckPlan(Long id, AssetCheckPlanUpdateRequest request) {
        log.info("开始更新盘点计划，计划ID：{}，请求参数：{}", id, request);

        AssetCheckPlan plan = getById(id);
        if (plan == null) {
            log.error("盘点计划不存在，计划ID：{}", id);
            throw new RuntimeException("盘点计划不存在");
        }

        // 只有未开始的盘点计划可以修改
        if (!"NOT_STARTED".equals(plan.getStatus())) {
            log.error("只有未开始的盘点计划可以修改，当前状态：{}，计划ID：{}", plan.getStatus(), id);
            throw new RuntimeException("只有未开始的盘点计划可以修改");
        }

        // 验证更新请求参数
        validateUpdateRequest(request);

        plan.setCheckScope(request.getCheckScope());
        plan.setScopeId(request.getScopeId());
        plan.setCheckUserId(request.getCheckUserId());
        plan.setStartTime(request.getStartTime());
        plan.setEndTime(request.getEndTime());
        plan.setUpdateTime(LocalDateTime.now());

        saveOrUpdate(plan);
        log.info("盘点计划更新成功，计划ID：{}", id);

        return plan;
    }

    @Override
    @Transactional
    public AssetCheckPlan startAssetCheckPlan(Long id) {
        log.info("开始启动盘点计划，计划ID：{}", id);

        AssetCheckPlan plan = getById(id);
        if (plan == null) {
            log.error("盘点计划不存在，计划ID：{}", id);
            throw new RuntimeException("盘点计划不存在");
        }

        if (!"NOT_STARTED".equals(plan.getStatus())) {
            log.error("只有未开始的盘点计划可以启动，当前状态：{}，计划ID：{}", plan.getStatus(), id);
            throw new RuntimeException("只有未开始的盘点计划可以启动");
        }

        // 检查盘点计划时间是否合理
        if (plan.getStartTime().isAfter(LocalDateTime.now())) {
            log.error("盘点计划开始时间不能晚于当前时间，计划ID：{}", id);
            throw new RuntimeException("盘点计划开始时间不能晚于当前时间");
        }

        plan.setStatus("IN_PROGRESS");
        plan.setUpdateTime(LocalDateTime.now());

        saveOrUpdate(plan);
        log.info("盘点计划启动成功，计划ID：{}", id);

        return plan;
    }

    @Override
    @Transactional
    public AssetCheckPlan completeAssetCheckPlan(Long id) {
        log.info("开始完成盘点计划，计划ID：{}", id);

        AssetCheckPlan plan = getById(id);
        if (plan == null) {
            log.error("盘点计划不存在，计划ID：{}", id);
            throw new RuntimeException("盘点计划不存在");
        }

        if (!"IN_PROGRESS".equals(plan.getStatus())) {
            log.error("只有进行中的盘点计划可以完成，当前状态：{}，计划ID：{}", plan.getStatus(), id);
            throw new RuntimeException("只有进行中的盘点计划可以完成");
        }

        // 检查盘点计划是否已到截止时间
        if (plan.getEndTime().isAfter(LocalDateTime.now())) {
            log.warn("盘点计划尚未到截止时间，计划ID：{}，当前时间：{}，截止时间：{}",
                    id, LocalDateTime.now(), plan.getEndTime());
        }

        plan.setStatus("COMPLETED");
        plan.setUpdateTime(LocalDateTime.now());

        saveOrUpdate(plan);
        log.info("盘点计划完成，计划ID：{}", id);
        // 生成盘点差异
        assetCheckDiffService.generateCheckDiffs(plan.getId());
        return plan;
    }

    @Override
    public List<AssetCheckPlan> getAssetCheckPlans(String status, Long checkUserId) {
        log.info("查询盘点计划列表，状态：{}，盘点人ID：{}", status, checkUserId);

        QueryWrapper<AssetCheckPlan> queryWrapper = new QueryWrapper<>();

        if (status != null && !status.isEmpty()) {
            queryWrapper.eq("status", status);
        }

        if (checkUserId != null) {
            queryWrapper.eq("check_user_id", checkUserId);
        }

        queryWrapper.orderByDesc("create_time");

        List<AssetCheckPlan> plans = list(queryWrapper);
        log.info("查询到{}个盘点计划", plans.size());

        return plans;
    }
        @Override
        @Transactional
        public AssetCheckPlan cancelAssetCheckPlan(Long id) {
            log.info("开始取消盘点计划，计划ID：{}", id);

            AssetCheckPlan plan = getById(id);
            if (plan == null) {
                log.error("盘点计划不存在，计划ID：{}", id);
                throw new RuntimeException("盘点计划不存在");
            }

            if (!"NOT_STARTED".equals(plan.getStatus())) {
                log.error("只有未开始的盘点计划可以取消，当前状态：{}，计划ID：{}", plan.getStatus(), id);
                throw new RuntimeException("只有未开始的盘点计划可以取消");
            }

            plan.setStatus("CANCELLED");
            plan.setUpdateTime(LocalDateTime.now());

            saveOrUpdate(plan);
            log.info("盘点计划取消成功，计划ID：{}", id);

            return plan;
        }



    /**
     * 根据盘点范围查询资产ID列表
     * @param checkScope 盘点范围
     * @param scopeId 范围ID
     * @return 资产ID列表
     */
    private List<Long> getAssetIdsByCheckScope(String checkScope, Long scopeId) {
        QueryWrapper<AssetInfo> queryWrapper = new QueryWrapper<>();

        switch (checkScope) {
            case "ALL":
                // 全量盘点，查询所有资产
                break;
            case "DEPT":
                // 部门盘点，查询指定部门的资产
                if (scopeId == null) {
                    throw new RuntimeException("部门盘点时部门ID不能为空");
                }
                queryWrapper.eq("dept_id", scopeId);
                break;
            case "CATEGORY":
                // 分类盘点，查询指定分类的资产
                if (scopeId == null) {
                    throw new RuntimeException("分类盘点时分类ID不能为空");
                }
                queryWrapper.eq("category_id", scopeId);
                break;
            default:
                throw new RuntimeException("不支持的盘点范围：" + checkScope);
        }

        // 只查询状态为正常的资产
        queryWrapper.eq("status", "NORMAL");

        List<AssetInfo> assetInfos = assetInfoService.list(queryWrapper);
        return assetInfos.stream()
                .map(AssetInfo::getId)
                .collect(Collectors.toList());
    }

    /**
     * 验证创建请求参数
     * @param request 创建请求
     */
    private void validateCreateRequest(AssetCheckPlanCreateRequest request) {
        if (request.getStartTime().isAfter(request.getEndTime())) {
            throw new RuntimeException("开始时间不能晚于结束时间");
        }

        if (request.getStartTime().isBefore(LocalDateTime.now())) {
            throw new RuntimeException("开始时间不能早于当前时间");
        }

        // 验证盘点范围参数
        if (!"ALL".equals(request.getCheckScope()) &&
                !"DEPT".equals(request.getCheckScope()) &&
                !"CATEGORY".equals(request.getCheckScope())) {
            throw new RuntimeException("盘点范围必须是ALL、DEPT或CATEGORY");
        }

        // 如果是部门或分类盘点，scopeId不能为空
        if (!"ALL".equals(request.getCheckScope()) && request.getScopeId() == null) {
            throw new RuntimeException(request.getCheckScope() + "盘点时范围ID不能为空");
        }
    }

    /**
     * 验证更新请求参数
     * @param request 更新请求
     */
    private void validateUpdateRequest(AssetCheckPlanUpdateRequest request) {
        if (request.getStartTime().isAfter(request.getEndTime())) {
            throw new RuntimeException("开始时间不能晚于结束时间");
        }

        if (request.getStartTime().isBefore(LocalDateTime.now())) {
            throw new RuntimeException("开始时间不能早于当前时间");
        }

        // 验证盘点范围参数
        if (!"ALL".equals(request.getCheckScope()) &&
                !"DEPT".equals(request.getCheckScope()) &&
                !"CATEGORY".equals(request.getCheckScope())) {
            throw new RuntimeException("盘点范围必须是ALL、DEPT或CATEGORY");
        }

        // 如果是部门或分类盘点，scopeId不能为空
        if (!"ALL".equals(request.getCheckScope()) && request.getScopeId() == null) {
            throw new RuntimeException(request.getCheckScope() + "盘点时范围ID不能为空");
        }
    }

    /**
     * 生成盘点计划编号
     * @return 盘点计划编号
     */
    private String generatePlanNo() {
        return "CP" + System.currentTimeMillis() + UUID.randomUUID().toString().substring(0, 4).toUpperCase();
    }
}